<template>
  <div id="container">
    <div id="mask" :style="{ bottom: offsetBottom + 'px' }">
      <!-- 曲线轨迹的 canvas 元素 -->
      <canvas
        ref="flightCanvas"
        width="1500"
        height="10000"
        class="flight-track"
      />
      <!-- 小红点轨迹的 canvas 元素 -->
      <canvas ref="dotCanvas" width="1500" height="10000" class="dot-track" />
    </div>
    <!-- 预览图的 canvas 元素 -->
    <div class="preview">
      <canvas ref="previewCanvas" width="200" height="1000" />
    </div>
  </div>
</template>
<script>
import { mapGetters } from "vuex";
import { trackData } from "./trackData";
import PubSub from "pubsub-js";

export default {
  data() {
    return {
      // difficultys: 1, // 默认难度
      flightCanvas: null, // 存储飞行轨迹的canvas元素
      flightCtx: null, // 存储飞行轨迹canvas的2D绘图上下文
      dotCanvas: null, // 存储小红点轨迹的canvas元素
      dotCtx: null, // 存储小红点轨迹canvas的2D绘图上下文
      previewCanvas: null, // 存储预览图的canvas元素
      previewCtx: null, // 存储预览图canvas的2D绘图上下文
      canvasWidth: 1500, // 主画布的宽度
      canvasHeight: 10000, // 主画布的高度
      previewWidth: 200, // 预览图的宽度
      previewHeight: 1000, // 预览图的高度
      totalHeight: 10000, // 总高度
      lineWidth: 6, // 轨迹线条的宽度
      duration: 60000, // 动画持续时间（1分钟）
      animationFrameId: null, // requestAnimationFrame的ID，用于动画控制
      track: [], // 存储生成的轨迹点
      startTimer: null, // 定时器ID，用于发送小红点位置
      moveTimer: null, // requestAnimationFrame的ID，用于移动背景
      maskElement: null, // 存储#mask元素
      offsetBottom: 0, // 用于控制mask元素的偏移量
      previewTimer: null,
    };
  },
  computed: {
    ...mapGetters(["bgSpeed", "gameConfig", "getWebSocket"]),
  },
  mounted() {
    this.maskElement = document.getElementById("mask");
    this.flightCanvas = this.$refs.flightCanvas;
    this.flightCtx = this.flightCanvas.getContext("2d");
    this.dotCanvas = this.$refs.dotCanvas;
    this.dotCtx = this.dotCanvas.getContext("2d");
    this.previewCanvas = this.$refs.previewCanvas;
    this.previewCtx = this.previewCanvas.getContext("2d");
    this.startGame();
  },
  beforeDestroy() {
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId);
    }
    if (this.startTimer) {
      clearInterval(this.startTimer);
    }
    if (this.moveTimer) {
      clearInterval(this.moveTimer);
    }
    if (this.previewTimer) {
      clearInterval(this.previewTimer);
    }
  },
  methods: {
    // 根据难度生成随机轨迹
    generateTrack(difficulty) {
      const track = [];
      let numPoints;
      let maxAmplitude;

      switch (difficulty) {
        case "1":
          numPoints = 10;
          maxAmplitude = 300;
          break;
        case "2":
          numPoints = 20;
          maxAmplitude = 400;
          break;
        case "3":
          numPoints = 30;
          maxAmplitude = 500;
          break;
        case "4":
          numPoints = 40;
          maxAmplitude = 600;
          break;
        default:
          numPoints = 40;
          maxAmplitude = 500;
      }

      for (let i = 0; i < numPoints; i++) {
        const x = this.canvasWidth / 2 + (Math.random() - 0.5) * maxAmplitude;
        const y = (i / numPoints) * this.totalHeight;
        track.push({ x, y });
      }

      return track;
    },
    // 生成平滑的贝塞尔曲线点
    generateBezierCurvePoints(track, numPoints) {
      const bezierPoints = [];
      const n = track.length - 1;

      for (let i = 0; i < n; i++) {
        const p0 = i === 0 ? track[i] : track[i - 1];
        const p1 = track[i];
        const p2 = track[i + 1];
        const p3 = i === n - 1 ? track[i + 1] : track[i + 2];

        for (let t = 0; t < 1; t += 1 / numPoints) {
          const x =
            0.5 *
            ((-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * t * t * t +
              (2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * t * t +
              (-p0.x + p2.x) * t +
              2 * p1.x);
          const y =
            0.5 *
            ((-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t * t * t +
              (2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t * t +
              (-p0.y + p2.y) * t +
              2 * p1.y);
          bezierPoints.push({ x, y });
        }
      }
      return bezierPoints;
    },
    // 在canvas上绘制轨迹
    drawTrack(ctx, track, width, height, scaleX, scaleY, lineWidth) {
      ctx.beginPath();
      ctx.moveTo(track[0].x * scaleX, height - track[0].y * scaleY);

      for (let i = 1; i < track.length - 2; i++) {
        const cp1x = ((track[i].x + track[i + 1].x) / 2) * scaleX;
        const cp1y = height - ((track[i].y + track[i + 1].y) / 2) * scaleY;
        ctx.quadraticCurveTo(
          track[i].x * scaleX,
          height - track[i].y * scaleY,
          cp1x,
          cp1y
        );
      }

      ctx.strokeStyle = "lime";
      ctx.lineWidth = lineWidth;
      ctx.shadowColor = "lime";
      ctx.shadowBlur = 10;
      ctx.stroke();
    },
    // 在canvas上绘制小红点
    drawDot(ctx, x, y, radius = 15, color = "red") {
      ctx.beginPath();
      ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
      ctx.fillStyle = color;
      ctx.fill();
    },
    // 线性插值函数
    lerp(start, end, t) {
      return start + (end - start) * t;
    },
    // 动画小红点沿着轨迹移动
    animateDot(track) {
      const startTime = Date.now();
      let previousX, previousY;
      const animate = () => {
        const currentTime = Date.now();
        const elapsedTime = currentTime - startTime;
        const t = Math.min(1, elapsedTime / this.duration);
        const currentPointIndex = Math.floor(t * (track.length - 1));
        const nextPointIndex = Math.min(
          currentPointIndex + 1,
          track.length - 1
        );
        const localT =
          (t - currentPointIndex / (track.length - 1)) * (track.length - 1);
        const currentPoint = track[currentPointIndex];
        const nextPoint = track[nextPointIndex];
        const x = this.lerp(currentPoint.x, nextPoint.x, localT);
        const y = this.lerp(currentPoint.y, nextPoint.y, localT);

        const dotYInView =
          this.canvasHeight - y / (this.totalHeight / this.canvasHeight);
        // 仅清除小红点区域并重新绘制小红点
        if (previousX !== undefined && previousY !== undefined) {
          this.dotCtx.clearRect(previousX - 20, previousY - 20, 40, 40);
        }
        this.drawDot(this.dotCtx, x, dotYInView);
        previousX = x;
        previousY = dotYInView;

        if (elapsedTime < this.duration) {
          this.animationFrameId = requestAnimationFrame(animate);
        }
      };

      animate();
    },
    // 绘制预览图
    drawPreview(track) {
      const scaleX = this.previewWidth / this.canvasWidth;
      const scaleY = this.previewHeight / this.canvasHeight;
      this.drawTrack(
        this.previewCtx,
        track,
        this.previewWidth,
        this.previewHeight,
        scaleX,
        scaleY,
        2
      );
    },
    clear() {
      this.flightCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
      this.dotCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
      this.previewCtx.clearRect(0, 0, this.previewWidth, this.previewHeight);
      this.offsetBottom = 0;
      if (this.animationFrameId) {
        cancelAnimationFrame(this.animationFrameId);
      }
      if (this.startTimer) {
        clearInterval(this.startTimer);
      }
      if (this.moveTimer) {
        clearInterval(this.moveTimer);
      }
      if (this.previewTimer) {
        clearInterval(this.previewTimer);
      }
      if (this.gameConfig && this.gameConfig.gameMode == 2) {
        localStorage.removeItem("track");
      }
    },
    saveTrackDataToFile(track) {
      const dataStr = JSON.stringify(track);
      const dataUri =
        "data:application/json;charset=utf-8," + encodeURIComponent(dataStr);

      const exportFileDefaultName = "trackData.json";

      const linkElement = document.createElement("a");
      linkElement.setAttribute("href", dataUri);
      linkElement.setAttribute("download", exportFileDefaultName);
      linkElement.click();
    },
    // 开始游戏，初始化并启动动画
    startGame() {
      this.clear();
      this.bgMove();
      this.previewMove();
      let bezierPoints;
      let track;
      if (localStorage.getItem("gameMode") == 2) {
        track = this.generateTrack(
          this.gameConfig && this.gameConfig.gameDifficulty
        );
      } else {
        track = trackData[localStorage.getItem("setDifficulty") - 1];
      }

      bezierPoints = this.generateBezierCurvePoints(track, 5000);
      this.track = bezierPoints;
      this.drawTrack(
        this.flightCtx,
        bezierPoints,
        this.canvasWidth,
        this.canvasHeight,
        1,
        1,
        this.lineWidth
      ); // 原始大小的轨迹
      this.animateDot(bezierPoints);
      this.drawPreview(bezierPoints); // 绘制预览图
      let index = 0;
      let count = 0;
      this.startTimer = setInterval(() => {
        if (index < 195000) {
          let ballPoint = {
            id: count++,
            code: "ballPoint",
            time: +new Date(),
            data: this.track[index],
          };
          let planeSpeed = {
            id: count++,
            code: "planeSpeed",
            time: +new Date(),
            airplaneSpeed: this.bgSpeed * 36,
          };

          this.getWebSocket.send(JSON.stringify(ballPoint));
          this.getWebSocket.send(JSON.stringify(planeSpeed));
          index += 195;
        } else {
          clearInterval(this.startTimer);
        }
      }, 60);
    },
    bgMove() {
      this.moveTimer = setInterval(() => {
        if (this.maskElement.offsetTop > 0) {
          this.offsetBottom = 0; //轮询
          // clearInterval(this.moveTimer);
          // return;
        }
        this.offsetBottom = this.offsetBottom - this.bgSpeed / 2;
      }, 10);
    },
    previewMove() {
      let index = 60;
      this.previewTimer = setInterval(() => {
        if (this.previewCanvas.offsetTop < 40) {
          index -= this.bgSpeed / 3;
          this.previewCanvas.style.bottom = index + "px";
        } else {
          clearInterval(this.previewTimer);
          return;
        }
      }, 60);
    },
  },
};
</script>

<style scoped lang="scss">
#container {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;

  #mask {
    position: absolute;
    left: 0;
    width: 100%;
    height: 10600px;
    background-image: url("../../../../assets/images/fly1.png");
    background-size: cover;
    background-repeat: no-repeat;
    canvas {
      position: absolute;
      bottom: 300px;
      left: calc(50% - 750px);
    }

    // .flight-track {
    //   z-index: 1; /* 轨迹的层级较低 */
    // }

    // .dot-track {
    //   z-index: 2; /* 小红点的层级较高 */
    // }
  }

  .preview {
    position: absolute;
    right: 10px;
    top: 10px;
    width: 200px;
    height: 200px;
    overflow: auto;
    background: rgba($color: #000000, $alpha: 0.3);
    border-radius: 10px;
    canvas {
      position: absolute;
      left: 0;
      bottom: 60px;
    }
  }
}
</style>
